package czk.concrent.reentrantLock.wheellock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 二、使用轮询锁来解决它了，它的实现思路是通过轮询的方式来获取多个锁，如果中途有任意一个锁获取失败，则执行回退操作，释放当前线程拥有的所有锁，
 * 等待下一次重新执行，这样就可以避免多个线程同时拥有并霸占锁资源了，从而直接解决了死锁的问题，简易版的轮询锁实现如下：
 * 使用轮询解决死锁问题
 *
 * @Author:ChenZhangKun
 * @Date: 2021/8/31 10:14
 */
public class Demo2 {
    public static void main(String[] args) {
        Lock lock1 = new ReentrantLock();
        Lock lock2 = new ReentrantLock();

        new Thread(() -> {
            // 调用轮询锁
            pollingLock(lock1, lock2);
        }).start();

        new Thread(() -> {
            try {
                lock2.lock();
                System.out.println("线程二获取到锁：B");
                // 获取锁二
                Thread.sleep(1000);
                System.out.println("线程二等待获取锁：A");
                try {
                    lock1.lock();
                    System.out.println("线程二获取到了锁：A");
                } finally {
                    lock1.unlock();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock2.unlock();
            }
        }).start();
    }

    private static void pollingLock(Lock lock1, Lock lock2) {
        while (true) {
            if (lock1.tryLock()) {
                System.out.println("线程一拿到锁：A");
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println("线程一等待获取锁：B");
                    if (lock2.tryLock()) {
                        try {
                            // 获取到锁B
                            System.out.println("线程一获取到锁：B");
                        } finally {
                            System.out.println("线程一释放锁：B");
                            // 释放锁
                            lock2.unlock();
                            break;
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 释放锁A
                    lock1.unlock();
                    System.out.println("线程一释放锁A");
                }
            }
        }
    }
}
